package com.xiezc;

import com.xiezc.model.Device;
import com.xiezc.model.Packet;
import com.xiezc.model.SendProgress;
import lombok.Data;
import lombok.Setter;
import lombok.Synchronized;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;

import java.util.Iterator;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @author wb-xzc291800
 * @date 2018/09/05 15:15
 */
@Slf4j
public class RetPacketService {

    private ConcurrentHashMap<String, RetPacket> retPacketBuf = new ConcurrentHashMap<>();

    static RetPacketService retPacketService;

    @Setter
    private SendService sendService;

    private RetPacketService(int waitMillSecond, int maxSendCount) {

        this.waitMillSecond = waitMillSecond;
        this.maxSendCount = maxSendCount;
    }

    /**
     * 每个包的超时时间
     */
    final int waitMillSecond;

    /**
     * 每个包的重发次数
     */
    final int maxSendCount;

    @Synchronized
    static RetPacketService single(int waitSecond, int maxSendCount) {

        if (retPacketService == null) {
            retPacketService = new RetPacketService(waitSecond, maxSendCount);
        }
        log.info("RetPacketService 重发服务初始化完成......");
        return retPacketService;
    }

    void start() {

        Executors.newScheduledThreadPool(1)
            .scheduleWithFixedDelay(
                () -> {
                    long currentTime = System.currentTimeMillis();
                    Iterator<Entry<String, RetPacket>> iterator = retPacketBuf.entrySet().iterator();
                    while (iterator.hasNext()) {
                        Entry<String, RetPacket> next = iterator.next();
                        RetPacket value = next.getValue();

                        if (value.getSendCount() > maxSendCount) {
                            iterator.remove();
                            //消息发送失败
                            value.getSendProgress().setSuccess(false);
                            log.warn("重发次数超过了最大次数,删除这个数据包 maxSendCount:{} ", maxSendCount);
                            continue;
                        }

                        long sendTime = value.getSendTime();
                        long passTime = currentTime - sendTime;
                        if (passTime > waitMillSecond) {
                            //超时没有超过最大发送次数, 重发
                            Device device = value.getDevice();
                            if (Objects.isNull(device)) {
                                iterator.remove();
                                log.error("这个包的接受设备不在册, msgId:{}. index:{}", value.getMsgId(), value.getIndex());
                            }
                            //不用创建回复包的类型
                            if (value.getPtype().isRet()) {
                                iterator.remove();
                                log.warn("混入了不用重发的包.  msgId:{}. index:{} ,ptype:{}", value.getMsgId(), value.getIndex(),
                                    value.getPtype());
                                continue;
                            }

                            boolean b = sendService.addBuf(value, device);
                            if (b) {
                                value.setSendTime(currentTime);
                                value.setSendCount(value.getSendCount() + 1);
                            }
                        }
                    }

                }, 0, waitMillSecond * 2, TimeUnit.MILLISECONDS);
    }

    boolean add(RetPacket retPacket) {

        String key = createKey(retPacket);
        RetPacket put = retPacketBuf.put(key, retPacket);
        return !Objects.isNull(put);
    }

    boolean add(SendPacket packet, Device device) {

        RetPacket retPacket = new RetPacket();
        BeanUtils.copyProperties(packet, retPacket);
        retPacket.setDevice(device);
        retPacket.setSendTime(System.currentTimeMillis());
        retPacket.setSendCount(retPacket.getSendCount() + 1);
        return add(retPacket);

    }

    boolean removePacket(Packet retPacket) {

        String s = createKey(retPacket);
        RetPacket remove = retPacketBuf.remove(s);
        //刷新进度条
        boolean b = !Objects.isNull(remove);
        if (b) {
            SendProgress sendProgress = remove.getSendProgress();
            if (!Objects.isNull(sendProgress)) {
                sendProgress.sendCountAddOne();
            }
        }

        return b;
    }

    private String createKey(Packet retPacket) {

        return retPacket.getMsgId() + "_" + retPacket.getIndex();
    }

}

/**
 * @author wb-xzc291800
 * @date 2018/09/07 17:41
 */

@Data
class RetPacket extends Packet {

    /**
     * 包的send时间, 没重发一次, 这个时间更新一次
     */
    long sendTime;

    /**
     * 包的重发次数
     */
    int sendCount;

    Device device;

    SendProgress sendProgress;
}
